#include "Boot.h"
#include <math.h>

typedef void (*Load_A)(void);

Load_A load_a;
uint8_t BootLoader_Enter(uint8_t timeout);
void BootLoader_Info(void);

void BootLoader_Branch(void)
{
	if(BootLoader_Enter(20) == 0)
	{
		if(OTA_Info.OTA_flag == OTA_SET_FLAG)
		{
			printf("OTA Update\r\n");
			BootStateFlag |= UPDATE_APP_FLAG;
			return;	// 后面的命令行不应该执行
		}
		else
		{
			printf("Jump To APP\r\n");
			LOAD_APP(FLASH_PAGE1_SADDR);
			printf("Jump To APP Fail\r\n");
		}
	}
	// 如果跳转失败，则也应该进入命令行模式
	BootLoader_Info();

}

uint8_t BootLoader_Enter(uint8_t timeout)
{
	printf("%dms, Input w Enter BootLoader Sheel Mode\r\n", timeout * 100);
	while(timeout--)
	{
		delay_ms(100);
		if(USART1_RxBuff[0] == 'w')
		{
			// U1CB.U1RxDataOUT ++;
			return 1;		// 进入命令行
		}
	}
	return 0;				// 不进入命令行
}

uint16_t Xmodem_CRC16(uint8_t *data, uint16_t datalen)
{
	uint16_t CrcInit = 0x0000;
	uint16_t CrcIpoly = 0x1021;
	while(datalen--)
	{
		CrcInit = (*data << 8) ^ CrcInit;
		for(uint8_t i = 0; i < 8; i++)
		{
			if(CrcInit & 0x8000)
			{
				CrcInit = (CrcInit << 1) ^ CrcIpoly;
			}
			else
			{
				CrcInit = (CrcInit << 1);
			}
		}
		data++;
	}
	return CrcInit;
}


void BootLoader_Event(uint8_t *data, uint16_t datalen)
{
	if(BootStateFlag == 0)
	{
		if(datalen ==  1)
		{
			if(data[0] == '1')
			{
				printf("By USART IAP DOWNLOAD APP\r\n");
				// 确定擦除的块数，与F1不同之处
				uint8_t bNUM;
				// ***逻辑测试通过
				bNUM = (uint8_t)OTA_Info.UpdateLen <=48 ?  ceil(1.0 * OTA_Info.UpdateLen / 16) : 
					  (OTA_Info.UpdateLen <= 112 ? 4 : 
					   4 + ceil((1.0 * OTA_Info.UpdateLen - 112) / 128));	// 在896K-1MB区域暂时不做考虑
				
				// 擦除内部flash中对应的写区域
				if( bNUM && (IN_Flash_Erease(APP_START_PAGE, bNUM) != HAL_OK))
					printf("IN FLASH ERASE FAIL!\r\n");
				BootStateFlag |= (IAP_XMODEM_FLAG | IAP_XMODEM_DATA);
				updateA.XmodemTimer = 0;
				updateA.XmodemNUM = 0;
			}
			else if(data[0] == '2')
			{
				NVIC_SystemReset();
			}
			else if(data[0] == '3')
			{
				if(IN_Flash_Erease(APP_START_PAGE, 1) != HAL_OK)
					printf("IN FLASH ERASE FAIL!\r\n");
				else
					printf("Erase OK\r\n");
				BootLoader_Branch();
			}
			else if(data[0] == '4')
			{
				// Update By W25Q128
				uint8_t bNUM;
				bNUM = (uint8_t)OTA_Info.UpdateLen <=48 ?  ceil(1.0 * OTA_Info.UpdateLen / 16) : 
					  (OTA_Info.UpdateLen <= 112 ? 4 : 
					   4 + ceil((1.0 * OTA_Info.UpdateLen - 112) / 128));	// 在896K-1MB区域暂时不做考虑
				if( bNUM && (IN_Flash_Erease(APP_START_PAGE, bNUM) != HAL_OK))
					printf("IN FLASH ERASE FAIL!\r\n");
				
				// Start Update
				for(uint8_t i = 0; i < OTA_Info.UpdateLen; i++)
				{
					W25Q128_Read(updateA.UpdateBuff, W25Q128_PAGE_SIZE * i, W25Q128_PAGE_SIZE);
					if(IN_Flash_Write(APP_START_ADDR + (W25Q128_PAGE_SIZE * i), 
										(uint32_t *)updateA.UpdateBuff, W25Q128_PAGE_SIZE / FLASH_WORD_SIZE) != HAL_OK)
					{
						printf("Page %d Write To FLASH Filed!\r\n", i);
					}
				}
			}
				
		}
	}
	if(BootStateFlag & IAP_XMODEM_DATA)
	{
		if((datalen == 133) && (data[0] == 0x01))
		{
			
			BootStateFlag &= ~IAP_XMODEM_FLAG;	// 停止发送起始C字符
			updateA.XmodemCRC = Xmodem_CRC16(&data[3], 128);
			if(updateA.XmodemCRC == ((data[131] << 8) | data[132]))
			{
//				updateA.XmodemNUM++;
//				memcpy(&updateA.UpdateBuff[((updateA.XmodemNUM - 1) % (W25Q128_PAGE_SIZE / 128)) * 128], &data[3], 128);
				memcpy(&updateA.UpdateBuff[((updateA.XmodemNUM++) % (W25Q128_PAGE_SIZE / 128)) * 128], &data[3], 128);
				if((updateA.XmodemNUM % (W25Q128_PAGE_SIZE / 128)) == 0)	// 已经够一页（1KB）（对于内部flash是错误的）
				{
					if(IN_Flash_Write(APP_START_ADDR + ((updateA.XmodemNUM / (W25Q128_PAGE_SIZE / 128)) - 1) * W25Q128_PAGE_SIZE,
									  (uint32_t *)updateA.UpdateBuff, W25Q128_PAGE_SIZE) != HAL_OK)
						printf("IN FLASH WRITE FAIL!\r\n");
				}
				printf("\x06");	// ACK
			}
			else
			{
				printf("\x15");	// NACK
			}
		}
		if((datalen == 1) && (data[0] == 0x04))
		{
			printf("\x06");
			if(IN_Flash_Write(APP_START_ADDR + ((updateA.XmodemNUM / (W25Q128_PAGE_SIZE / 128))) * W25Q128_PAGE_SIZE,
									  (uint32_t *)updateA.UpdateBuff, W25Q128_PAGE_SIZE) != HAL_OK)
				printf("IN FLASH ERASE FAIL!\r\n");
			BootStateFlag &= ~IAP_XMODEM_FLAG;
			delay_ms(100);
			NVIC_SystemReset();
			
		}
	}	
}

	
void BootLoader_Info(void)
{
	printf("\r\n");
	printf("[1]USART IAP APP\r\n");
	printf("[2]ReStart\r\n");
	printf("[3]Erase Block\r\n");
	printf("[4]UPDATE BY OUT FLASH\r\n");
	printf("[1]\r\n");
	
}



static void Boot_DeInit(void)
{
    // 关闭外设
    HAL_UART_DeInit(&huart1);
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8 | GPIO_PIN_9);
    HAL_SPI_DeInit(&hspi);

    // 关 SysTick
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL  = 0;

    // 关中断
    for (uint8_t i = 0; i < 8; i++) {
        NVIC->ICER[i] = 0xFFFFFFFF;
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }
}

// 设置SP指针
__asm void MSR_SP(uint32_t addr) {
    MSR MSP, R0
    BX  LR
}

// 跳转 APP
void LOAD_APP(uint32_t addr)
{
    uint32_t appStack = *(uint32_t *)addr;
    uint32_t appResetHandler = *(uint32_t *)(addr + 4);

    if ((appStack >= 0x20000000) && (appStack <= 0x20020000))  // F4 128KB RAM
    {
        Boot_DeInit();                // 先清 Boot 外设
        MSR_SP(appStack);             // 设置栈顶
        load_a = (Load_A)appResetHandler;
        load_a();                     // 跳到 APP Reset_Handler
    }
}




